package com.ylr.base.common.utils;

import com.ylr.base.common.po.user.UserPo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * Created by IntelliJ IDEA.
 *
 * @author wyw
 * date: 2023-05-03 21:42:18
 * className: ThrottleUtils 节流执行异步任务工具类
 * version: 1.0
 * description:
 */
public class ThrottleUtils {

    private static final Logger log = LoggerFactory.getLogger(ThrottleUtils.class);

    private final ScheduledThreadPoolExecutor scheduledThreadPoolExecutor;

    private final ConcurrentHashMap<String, Boolean> map = new ConcurrentHashMap<>();

    public ThrottleUtils(ScheduledThreadPoolExecutor scheduledThreadPoolExecutor) {
        this.scheduledThreadPoolExecutor = scheduledThreadPoolExecutor;
    }

    /**
     * 运行节流方法
     * 根据参数键进行节流操作
     * @param runnable 目标方法
     * @param key      键
     * @param delay    延时时长
     * @param unit     单位
     */
    public void throttleRun(Runnable runnable, String key, long delay, TimeUnit unit) {
        log.debug("节流执行（{}）任务", key);
        if (Objects.isNull(map.put(key, Boolean.TRUE))) {
            // 获取调用线程存储的请求用户数据
            UserPo userPo = UserUtils.getUser();
            Runnable _runnable = () -> {
                try {
                    // 设置请求用户
                    UserUtils.setUser(userPo);
                    // 执行目标方法
                    runnable.run();
                } finally {
                    // 清理请求用户
                    UserUtils.deleteUser();
                    // 删除key
                    map.remove(key);
                }
            };
            scheduledThreadPoolExecutor.schedule(_runnable, delay, unit);
        }
    }

    /**
     * 删除节流key操作
     * @param key 键
     * @return 删除结果[true-键存在且删除 false-键不存在]
     */
    public boolean removeKey(String key) {
        return map.remove(key);
    }

    /**
     * 清空所有key操作
     */
    public void clearKey() {
        map.clear();
    }
}
